﻿using System.IO.Compression;
using System.Net;
using SharpCompress.Common;

namespace Zero.WebAPI.Framework.Common
{
    public class CompressedContent : HttpContent
    {
        private readonly HttpContent _originalContent; // 存储原始的 HttpContent 对象
        private readonly CompressionType _compressionMethod; // 存储压缩方法

        /// <summary>
        /// 构造函数，初始化 CompressedContent 对象
        /// </summary>
        /// <param name="content">原始的 HttpContent 对象</param>
        /// <param name="compressionMethod">压缩方法（GZip 或 Deflate）</param>
        public CompressedContent(HttpContent content, CompressionType compressionMethod)
        {
            if (content == null)
            {
                throw new ArgumentNullException("content");
            }

            // 初始化原始内容
            _originalContent = content;

            // 初始化压缩方法
            _compressionMethod = compressionMethod;

            // 将原始内容的所有头部信息复制到新的 CompressedContent 对象中
            foreach (KeyValuePair<string, IEnumerable<string>> header in _originalContent.Headers)
            {
                Headers.TryAddWithoutValidation(header.Key, header.Value);
            }

            // 添加 Content-Encoding 头部，说明所使用的压缩方法
            Headers.ContentEncoding.Add(_compressionMethod.ToString().ToLowerInvariant());
        }

        /// <summary>
            /// 重写基类的TryComputeLength方法，直接设置长度为-1，返回false
            /// </summary> 
        protected override bool TryComputeLength(out long length)
        {
            length = -1;
            return false;
        }

        /// <summary>
            /// 重写基类的SerializeToStreamAsync方法，异步序列化内容到指定的流中
            /// </summary>
            /// <param name="stream">目标流</param>
            /// <param name="context">传输上下文</param>
            /// <returns>任务对象</returns>
        protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context)
        {
            if (_compressionMethod == CompressionType.GZip)
            {
                using (var gzipStream = new GZipStream(stream, CompressionMode.Compress, leaveOpen: true))
                {
                    await _originalContent.CopyToAsync(gzipStream);
                }
            }
            else if (_compressionMethod == CompressionType.Deflate)
            {
                using (var deflateStream = new DeflateStream(stream, CompressionMode.Compress, leaveOpen: true))
                {
                    await _originalContent.CopyToAsync(deflateStream);
                }
            }
        }
    }
}
